#ifndef ORBHELPER_H
#define ORBHELPER_H

#include <stdio.h>
#include <stdint.h>
#include <poll.h>
#include <uORB/uORB.h>
#include "NoCopy.h"

namespace orbhelper {

/* Workaround for the "defined in discarded subsection" linker error.
 * A template can't be instantiated more than in one module.
 * Place #define ORBSUBSCRIBER_WORKAROUND_NAMESPACE some_uniq_name
 * before #include <common/orbhelper.h> if you get such error.
 */
#if defined(ORBSUBSCRIBER_WORKAROUND_NAMESPACE)
namespace ORBSUBSCRIBER_WORKAROUND_NAMESPACE {
#endif

template<typename T, const orb_metadata *meta>
class __EXPORT OrbSubscriber : NoCopy {
public:
	OrbSubscriber() : sub_(-1), data_((const T){0}) {}

	~OrbSubscriber() {
		orb_unsubscribe(sub_);
	}

	bool update(bool check = false) {
		if (!subscribe())
			return false;

		if (check) {
			bool updated = false;
			if (orb_check(sub_, &updated) != OK)
				return false;
			if (!updated)
				return true;
		}

		return orb_copy(meta, sub_, &data_) == OK;
	}
	
	bool pollUpdate(uint32_t timeout) {
		if (!subscribe())
			return false;

		pollfd fd;
		fd.fd = sub_;
		fd.events = POLLIN;
		return poll(&fd, 1, timeout) > 0 && (fd.revents & POLLIN) && update();
	}

	const T& operator*() const {
		return data_;
	}

	const T* operator->() const {
		return &data_;
	}

private:
	bool subscribe() {
		if (sub_ <= 0)
			sub_ = orb_subscribe(meta);
		return sub_ > 0;
	}

	int sub_;
	T data_;
};

#if defined(ORBSUBSCRIBER_WORKAROUND_NAMESPACE)
}
#define OrbSubscriber ORBSUBSCRIBER_WORKAROUND_NAMESPACE::OrbSubscriber
#endif


template<typename T, const orb_metadata *meta>
class __EXPORT OrbPublisher : NoCopy {
public:
	OrbPublisher() : pub_(-1), data_((const T){0}) {}

	~OrbPublisher() {
		close(pub_);
	}

	void publish() {
		if (pub_ > 0)
			orb_publish(meta, pub_, &data_);
		else
			pub_ = orb_advertise(meta, &data_);
	}

	T& operator*() {
		return data_;
	}

	T* operator->() {
		return &data_;
	}

private:
	orb_advert_t pub_;
	T data_;
};

}

#endif
